package org.nowcoder.huawei.other;

import java.util.Stack;

public class Exp {
    //运算数
    private static int parseDigit(String val, int k) {
        StringBuilder build = new StringBuilder();
        for (int i = k; i < val.length(); i++) {
            if (Character.isDigit(val.charAt(i))) {
                build.append(val.charAt(i));
            } else {
                break;
            }
        }
        return Integer.parseInt(build.toString());
    }

    //计算表达式结果
    private static int cal(int left, int right, Character op) {
        switch (op) {
            case '+':
                return left + right;
            case '-':
                return left - right;
            case '*':
                return left * right;
            case '/':
                return left / right;
            default:
                return 0;
        }
    }

    //运算符优先级
    private static final String LEVEL_OPS = "+-*/";

    private static int opsPriority(char c1, char c2) {
        //c1 栈顶运算符，>= 0 表示栈顶运算符优先级更高，弹栈计算
        return LEVEL_OPS.indexOf(c1) - LEVEL_OPS.indexOf(c2);
    }

    public static int doubleStack(String val) {
        Stack<Integer> digits = new Stack<>();
        Stack<Character> ops = new Stack<>();

        for (int i = 0; i < val.length(); i++) {
            char c = val.charAt(i);
            if (i == 0 && c == '-') { //处理第一个元素是负数情况
                char cc = val.charAt(i + 1);
                if (Character.isDigit(cc)) {
                    int num = parseDigit(val, i + 1);
                    digits.push(0 - num);
                    i = i + ("" + num).length();
                    continue;
                }
            }

            if (Character.isDigit(c)) { //数字解析，数字入栈
                int num = parseDigit(val, i);
                digits.push(num);
                i = i + ("" + num).length() - 1;
            } else { //运算符解析
                if (c == '(') {
                    ops.push(c);
                    char cc = val.charAt(i + 2); // 处理 ( -1 为负数的情况
                    if (val.charAt(i + 1) == '-' && Character.isDigit(cc)) {
                        int num = parseDigit(val, i + 2);
                        digits.push(0 - num);
                        i = i + ("" + num).length() + 1;
                    }
                } else if (c == ')') {
                    while (!ops.isEmpty()) {
                        char op = ops.pop();
                        if (op != '(') {
                            int right = digits.pop();
                            int left = digits.pop();
                            //System.out.println("aaa--- " + left + " " + op + " " + right);
                            digits.push(cal(left, right, op));
                        } else {
                            break;
                        }
                    }
                } else {
                    while (!ops.isEmpty()) {
                        char op = ops.pop();
                        if (op != '(' && opsPriority(op, c) >= 0) {
                            int right = digits.pop();
                            int left = digits.pop();
                            //System.out.println("bbb--- " + left + " " + op + " " + right);
                            digits.push(cal(left, right, op));
                        } else {
                            ops.push(op);
                            break;
                        }
                    }
                    ops.push(c);
                }
            }
        }

        while (!ops.isEmpty()) {
            char op = ops.pop();
            int right = digits.pop();
            int left = digits.pop();
            //System.out.println("ccc--- " + left + " " + op + " " + right);
            digits.push(cal(left, right, op));
        }
        return digits.pop();
    }


    public static int singleStack(String val) {
        Stack<Integer> digits = new Stack<>();
        Stack<Character> ops = new Stack<>();

        //如何保存中缀表达式
        StringBuilder build = new StringBuilder(); //保存后缀表达式，中间用空格隔开
        for (int i = 0; i < val.length(); i++) {
            char c = val.charAt(i);

            //处理第一个元素是负数情况
            if (i == 0 && c == '-') {
                char cc = val.charAt(i + 1);
                if (Character.isDigit(cc)) {
                    String num = "-" + parseDigit(val, i + 1) + " ";
                    build.append(num);
                    i = i + num.length() - 2;
                    continue;
                }
            }

            //操作数，直接入栈
            if (Character.isDigit(c)) {
                String num = parseDigit(val, i) + " ";
                build.append(num);
                i = i + num.length() - 2;
            } else {
                //若是 ( 则直接入栈，并处理括号后第一个数是负数的情况
                if (c == '(') {
                    ops.push(c);

                    //处理 ( -1 为负数的情况
                    char cc = val.charAt(i + 2);
                    if (val.charAt(i + 1) == '-' && Character.isDigit(cc)) {
                        String num = "-" + parseDigit(val, i + 2) + " ";
                        build.append(num);
                        i = i + num.length() - 1;
                    }
                } else if (c == ')') {
                    //若是 ），则依次弹栈，加入到中缀表达式，直到 （
                    while (!ops.isEmpty()) {
                        char op = ops.pop();
                        if (op == '(') {
                            break;
                        } else {
                            build.append(op).append(" ");
                        }
                    }
                } else {
                    //若是操作符,根据优先级将操作符加入到中缀表达式或者栈中
                    //栈顶优先级更高,将运算符弹栈，加入到中缀表达式
                    if (ops.isEmpty()) {
                        ops.push(c);
                    } else {
                        while (!ops.isEmpty()) {
                            char op = ops.pop();
                            //优先级高于栈顶运算符，直接入栈
                            if (op == '(' || ((c == '*' || c == '/') && (op == '+' || op == '-'))) {
                                ops.push(op);
                                ops.push(c);
                                break;
                            } else {
                                build.append(op).append(" ");
                            }
                        }
                        if (ops.isEmpty()) ops.push(c);
                    }
                }
            }

        }
        while (!ops.isEmpty()) {
            build.append(ops.pop()).append(" ");
        }

        String[] exps = build.toString().trim().split(" ");
        System.out.println(build.toString());
        for (String tmp : exps) {
            if (tmp.equals("+") || tmp.equals("-") || tmp.equals("*") || tmp.equals("/")) {
                int right = digits.pop();
                int left = digits.pop();
                digits.push(cal(left, right, tmp.charAt(0)));
            } else {
                digits.push(Integer.parseInt(tmp));
            }
        }
        return digits.pop();
    }
}
